package crypt

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"io"
)

// ObfCrypt ...
type ObfCrypt struct {
	key string
}

// SetCryptKey ...
func (c *ObfCrypt) SetCryptKey(key string) error {
	c.key = key
	return nil
}

// ExistCryptKey ...
func (c *ObfCrypt) ExistCryptKey() bool {
	if c.key != "" {
		return true
	}
	return false
}

// Encrypt 加密
func (c *ObfCrypt) Encrypt(data []byte) (string,error) {
	if !c.ExistCryptKey() {
		return "", CryptKeynotFound
	}
	data = PKCS7Padding(data, aes.BlockSize)
	block, _ := aes.NewCipher([]byte(c.key))
	out := make([]byte, aes.BlockSize+len(data))
	iv := out[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return "", err
	}
	stream := cipher.NewOFB(block, iv)
	stream.XORKeyStream(out[aes.BlockSize:], data)
	return string(out),nil
}

// Decrypt 解密
func (c *ObfCrypt) Decrypt(source string) (interface{},error) {
	if !c.ExistCryptKey() {
		return nil, CryptKeynotFound
	}
	data := []byte(source)
	block, _ := aes.NewCipher([]byte(c.key))
	iv := data[:aes.BlockSize]
	data = data[aes.BlockSize:]
	if len(data)%aes.BlockSize != 0 {
		return nil, ObfNotMultipleSizeFail
	}
	out := make([]byte, len(data))
	mode := cipher.NewOFB(block, iv)
	mode.XORKeyStream(out, data)

	out = PKCS7UnPadding(out)
	return out,nil
}
